﻿/******************************************************************************
 * 【本类功能概述】                                 					      *
 *  版权所有（C）2017-20XX，匠梦科技                                         *
 *  保留所有权利。                                                            *
 ******************************************************************************
 *  作者 : <hughjk>
 *  创建时间:2019年5月19日 14:59:28
 *  文件描述:扩展代码
 *****************************************************************************/
using System;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
namespace Util
{
    public static class MathTool
    {
        public static int toAbs(this int s)
        {
            return Mathf.Abs(s);
        }

        public static float toAbs(this float s)
        {
            return Mathf.Abs(s);
        }

        public static int toInt(this int s)
        {
            return s;
        }

        public static int toInt(this float s)
        {
            return (int)s;
        }

        public static long toLong(this float s)
        {
            return (long)s;
        }

        public static float toFloat(this int s)
        {
            return (float)s;
        }

        public static Vector3 toVector3(this Vector2 vector)
        {
            return new Vector3(vector.x, vector.y);
        }

        public static T toEnum<T>(this int eunm)
        {
            T t = default(T);
            try
            {
                t = (T)(Enum.ToObject(typeof(T), eunm));
            }
            catch (System.Exception)
            {
                //debug.log("转枚举类似错误!!", eunm, typeof(T));
            }
            return t;
        }

        public static int toClamp(this int v, int min, int max)
        {
            return Mathf.Clamp(v, min, max);
        }

        public static float toClamp(this float v, float min, float max)
        {
            return Mathf.Clamp(v, min, max);
        }
        public static Vector2 toClamp(this Vector2 v, Vector2 min, Vector2 max)
        {
            v.x = Mathf.Clamp(v.x, min.x, max.x);
            v.y = Mathf.Clamp(v.y, min.y, max.y);
            return v;
        }
        public static Vector3 toClamp(this Vector3 v, Vector3 min, Vector3 max)
        {
            v.x = Mathf.Clamp(v.x, min.x, max.x);
            v.y = Mathf.Clamp(v.y, min.y, max.y);
            v.z = Mathf.Clamp(v.z, min.z, max.z);
            return v;
        }
        public static Vector3 toRandRange(this Vector3 v)
        {
            v.x = Random.Range(-v.x, v.x);
            v.y = Random.Range(-v.y, v.y);
            v.z = Random.Range(-v.z, v.z);
            return v;
        }
        public static bool toIsIn(this Vector3 v, Vector3 min, Vector3 max)
        {
            if (v.x >= min.x &&
                v.y >= min.y &&
                v.z >= min.z &&
                v.x <= max.x &&
                v.y <= max.y &&
                v.z <= max.z
                )
            {
                return true;
            }

            return false;
        }
        //世界位置是否在屏幕内
        public static bool toWorldPosIsInScreen(this Vector3 v)
        {
            Vector3 ScreenPos = Camera.main.WorldToScreenPoint(v);
            if (ScreenPos.toScreenPosIsInScreen())
            {
                return true;
            }
            return false;
        }
        //屏幕位置是否在屏幕内
        public static bool toScreenPosIsInScreen(this Vector3 v)
        {
            Vector3 ScreenSee = new Vector3(Screen.width, Screen.height, v.z);
            if (v.toIsIn(Vector3.zero, ScreenSee))
            {
                return true;
            }
            return false;
        }
        //屏幕位置转为屏幕内位置
        public static Vector3 toScreenInPos(this Vector3 v)
        {
            Vector3 ScreenSee = new Vector3(Screen.width, Screen.height, v.z);
            ScreenSee = v.toClamp(Vector3.zero, ScreenSee);
            return ScreenSee;
        }
        //屏幕位置转为屏幕内的世界位置
        public static Vector3 toScreenInWorldPos(this Vector3 v)
        {
            v = v.toScreenInPos();
            v = Camera.main.ScreenToWorldPoint(v);
            return v;
        }
        public static Vector3 toWorlPosToScreenInToWorldPos(this Vector3 v)
        {
            v = Camera.main.WorldToScreenPoint(v);
            v = v.toScreenInPos();
            v = Camera.main.ScreenToWorldPoint(v);
            return v;
        }
        public static Vector3 toWorlPosToScreenInPos(this Vector3 v)
        {
            v = Camera.main.WorldToScreenPoint(v);
            v = v.toScreenInPos();
            return v;
        }
        public static float to2dDistanceSquare(this Vector3 v, Vector3 endpos)
        {
            float dis = (v.x - endpos.x) * (v.x - endpos.x) + (v.y - endpos.y) * (v.y - endpos.y);
            return dis;
        }

        /// <summary>
        /// 概率幸运抽奖
        /// </summary>
        /// <param name="v"></param>
        /// <returns></returns>
        public static T toLucky<T>(this List<T> v)
        {
            T cur = default(T);
            if (v != null)
            {
                cur = v.ToArray().toLucky();
            }
            return cur;
        }

        /// <summary>
        /// 概率幸运抽奖
        /// </summary>
        /// <param name="v"></param>
        /// <returns></returns>
        public static T toLucky<T>(this T[] v)
        {
            T cur = default(T);
            if (v != null)
            {
                if (v.Length == 1)
                {
                    cur = v[0];
                }
                else if (v.Length > 1)
                {
                    int rand = UnityEngine.Random.Range(0, v.Length);
                    cur = v[rand];
                }
            }
            return cur;
        }

        /// <summary>
        /// 区间随机 数组1位3=>3,或者2位,2位取两者的区间,3-4=>3.5
        /// </summary>
        /// <param name="v"></param>
        /// <returns></returns>
        public static float toExtent(this List<float> v)
        {
            float cur = -1;
            if (v != null)
            {
                if (v.Count == 1)
                {
                    cur = v[0];
                }
                else if (v.Count == 2)
                {
                    cur = UnityEngine.Random.Range(v[0], v[1]);
                }
            }
            return cur;
        }

        /// <summary>
        /// 最后一位
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="v"></param>
        /// <returns></returns>
        public static T toLastOneData<T>(this List<T> v)
        {
            T cur = default(T);
            if (v.Count >= 1)
            {
                return v[v.Count - 1];
            }
            return cur;
        }

        /// <summary>
        /// 判断两个点的距离小于某个值
        /// </summary>
        public static bool toPosLTDic(this Vector3 pos1, Vector3 pos2, float dic)
        {
            return dic * dic > (pos1 - pos2).sqrMagnitude;
        }

        /// <summary>
        /// 判断两个点的距离小于某个值
        /// </summary>
        public static bool toPosLTDic(this Vector2 pos1, Vector2 pos2, float dic)
        {
            return dic * dic > (pos1 - pos2).sqrMagnitude;
        }
        public static Transform toPosMinDis(this Transform v, List<Component> list)
        {
            List<Transform> rf = new List<Transform>();
            for (int i = 0; i < list.Count; i++)
            {
                rf.Add(list[i].transform);
            }
            return v.toPosMinDis(rf);
        }
        //距离当前对象位置最近的一个
        public static Transform toPosMinDis(this Transform v,List<Transform> list)
        {
            float dis = int.MaxValue;
            Transform cv = v ;
            for (int i = 0; i < list.Count; i++)
            {
                if (v!= list[i])
                {
                    float cdis = (v.position - list[i].position).sqrMagnitude;
                    if (cdis< dis)
                    {
                        dis = cdis;
                        cv = list[i];
                    }
                }
            }
            return cv;
        }

        /// <summary>
        /// 保留几位小数
        /// </summary>
        public static float toRound(this float s, int num)
        {
            if (num > 0)
            {
                float b = (float)Mathf.Pow(10, num);
                float vs = s * b;
                long iv = (long)vs;
                s = (float)(iv / b);
            }
            return s;
        }

        /// <summary>
        /// 去除精度
        /// </summary>
        public static Vector3 toRemoveAccuracy(this Vector3 s)
        {
            s.x = s.x.toRound(2);
            s.y = s.y.toRound(2);
            s.z = s.z.toRound(2);
            return s;
        }

        public static Vector2 toVector2(this Vector3 s)
        {
            s.z = 0;
            return s;
        }

        /// <summary>
        /// 取其中的几位列如:123456.setSub(2,2);=&gt;34
        /// </summary>
        public static int sub(this int num, int str, int len)
        {
            if (len == 0)
            {
                return 0;
            }
            int newNum = num;
            int zlen = newNum.Length();
            int zend = zlen - str - len;
            zend = zend < 0 ? 0 : zend;
            if (zend > zlen)
            {
                //debug.log("超过截取范围!!!!");
                return 0;
            }
            newNum /= (int)Math.Pow(10, zend);
            newNum %= (int)Math.Pow(10, len);
            return newNum;
        }

        /// <summary>
        /// 替换其中的几位,列如:123456.setSub(2,78);=&gt;127856
        /// </summary>
        public static int setSub(this int num, int str, int news)
        {
            int mlen = num.Length();
            int nlen = news.Length();
            int zend = mlen - str - nlen;
            zend = zend < 0 ? 0 : zend;
            int baseDigit = (int)Math.Pow(10, zend);
            int dislodge = num.sub(str, nlen) * baseDigit;//抹去位的值
            news *= baseDigit;//得到位

            num = num - dislodge + news;
            return num;
        }

        /// <summary>
        /// 获取一个整形的位长度
        /// </summary>
        public static int Length(this int num)
        {
            int zlen = 0;
            float u = num;
            for (int i = 0; i < 99; i++)
            {
                if (u < 1)
                {
                    break;
                }
                u = u / 10;
                zlen++;
            }
            return zlen;
        }



        /// <summary>
        /// 在这个只区间内随机
        /// </summary>
        /// <param name="vector"></param>
        /// <returns></returns>
        public static Vector2 toRandom(this Vector2 vector)
        {
            Vector2 pos = new Vector2();
            pos.x = Random.Range(0, vector.x);
            pos.y = Random.Range(0, vector.y);
            return pos;
        }

        /// <summary>
        /// 范围内随机一个点
        /// </summary>
        /// <param name="box"></param>
        /// <returns></returns>
        public static Vector3 toRandomInPos(this BoxCollider2D box)
        {
            Vector3 pos = (box.size.toRandom() + box.offset).toVector3() + box.transform.position;
            return pos;
        }

        //public static List<Vector3> toRandomInPos(this BoxCollider2D box, float R, int Num)
        //{
        //    List<Vector3> vectors = new List<Vector3>();
        //    float rs = R / 2;
        //    int xl = (box.size.x / rs).toInt();
        //    int yl = (box.size.y / rs).toInt();
        //    for (int i = 0; i <= xl; i++)
        //    {
        //        for (int j = 0; j <= yl; j++)
        //        {
        //            Vector3 pos = new Vector3();
        //            pos.x = i * rs + box.offset.x - box.size.x / 2 + box.transform.position.x + Random.Range(-rs, rs);
        //            pos.y = j * rs + box.offset.y - box.size.y / 2 + box.transform.position.y + Random.Range(-rs, rs);
        //            vectors.Add(pos);
        //        }
        //    }
        //    vectors.RandomizeList();
        //    if (Num < vectors.Count)
        //    {
        //        vectors.RemoveRange(Num, vectors.Count - Num);
        //    }
        //    return vectors;
        //}

        /// <summary>
        /// 最大数量的内包含圆
        /// </summary>
        /// <param name="box"></param>
        /// <param name="R"></param>
        /// <returns></returns>
        public static int toMaxInCircle(this BoxCollider2D box, float R)
        {
            int MaxNum = (int)(box.size.x / R) * (int)(box.size.y / R);
            return MaxNum;
        }

        /// <summary>
        /// 判断一个多边形里面大楷有多少圆
        /// </summary>
        /// <param name="polygon"></param>
        /// <param name="R"></param>
        /// <returns></returns>
        public static int toMaxInCircle(this PolygonCollider2D polygon, float R)
        {
            int MaxNum = (polygon.toArea() / CircleArea(R)).toInt();
            MaxNum = MaxNum > 1 ? MaxNum - 1 : MaxNum;
            return MaxNum;
        }

        /// <summary>
        /// 矩形的面积
        /// </summary>
        /// <param name="box"></param>
        /// <returns></returns>
        public static float toArea(this BoxCollider2D box)
        {
            float Area = 0;
            Area = box.size.x * box.size.y;
            return Area;
        }

        /// <summary>
        /// 多边形的面积
        /// </summary>
        /// <param name="polygon"></param>
        /// <returns></returns>
        public static float toArea(this PolygonCollider2D polygon)
        {
            float Area = 0;
            for (int i = 0; i < polygon.pathCount; i++)
            {
                var pos = polygon.GetPath(i);
                Area += PolygonArea(pos);
            }
            return Area;
        }

        /// <summary>
        /// 计算多边形面积的函数
        /// (以原点为基准点,分割为多个三角形)
        /// 定理：任意多边形的面积可由任意一点与多边形上依次两点连线构成的三角形矢量面积求和得出。矢量面积=三角形两边矢量的叉乘。
        /// </summary>
        /// <param name="vectorPoints"></param>
        /// <returns></returns>
        public static float PolygonArea(Vector2[] vectorPoints)
        {
            int iCycle, iCount;
            iCycle = 0;
            float iArea = 0;
            iCount = vectorPoints.Length;

            for (iCycle = 0; iCycle < iCount; iCycle++)
            {
                iArea = iArea + (vectorPoints[iCycle].x * vectorPoints[(iCycle + 1) % iCount].y - vectorPoints[(iCycle + 1) % iCount].x * vectorPoints[iCycle].y);
            }

            return (float)Math.Abs(0.5 * iArea);
        }

        /// <summary>
        /// 计算圆的面积
        /// </summary>
        /// <param name="R"></param>
        /// <returns></returns>
        public static float CircleArea(float R)
        {
            return (float)(Math.PI * R * R);
        }

        /// <summary>
        /// 线性平滑到另外一个值
        /// </summary>
        public static float toLine(this float m, float v, float speed)
        {
            speed = Mathf.Abs(speed);
            float qv;
            if (m < v)
            {
                qv = v - speed;
                if (m > qv)
                {
                    qv = m;
                }
            }
            else
            {
                qv = v + speed;
                if (m < qv)
                {
                    qv = m;
                }
            }
            return qv;
        }

        /// <summary>
        /// 线性平滑到另外一个值
        /// </summary>
        public static Vector2 toLine(this Vector2 m, Vector2 v, float speed)
        {
            Vector2 dir = (v - m).normalized * speed;
            m.x = m.x.toLine(v.x, dir.x);
            m.y = m.y.toLine(v.y, dir.y);
            return m;
        }

        /// <summary>
        /// 线性平滑到另外一个值
        /// </summary>
        public static Vector3 toLine(this Vector3 m, Vector3 v, float speed)
        {
            Vector3 dir = (v - m).normalized * speed;
            m.x = m.x.toLine(v.x, dir.x);
            m.y = m.y.toLine(v.y, dir.y);
            m.z = m.y.toLine(v.z, dir.z);
            return m;
        }

        /// <summary>
        /// 获取两个点的2D距离的平方
        /// </summary>
        /// <param name="v1"></param>
        /// <param name="v2"></param>
        /// <returns></returns>
        public static float to2dDis(this Vector3 v1, Vector3 v2)
        {
            return (v1.x - v2.x) * (v1.x - v2.x) + (v1.y - v2.y) * (v1.y - v2.y);
        }

        public static float toRand(this Vector2 v1)
        {
            return Random.Range(v1.x, v1.y);
        }

        /// 将目标物体从开始点移动到目标点通过平滑的曲线
        ///
        /// 你要移动的目标物体
        /// 目标物体的开始点
        /// 目标物体的结束点
        /// 三个中间点
        /// 你最终得到的路径点的中间数,默认是20,数量越大曲线越平滑,越小越线性
        ///
        public static Vector3[] GetPathPoints(Transform start, Transform end, Transform[] threeCenterPosArr, int needPointNumber = 20)
        {
            //为了节省性能
            //将其转化成;一个float,可以进行差值运算,否则结果为0
            float number = (float)needPointNumber;
            //定义一个数组,用来存放路径点,他的长度是从0 - needPointNumber的长度,及从0-1
            Vector3[] targetPosArr = new Vector3[needPointNumber + 1];
            //只有在等于needPointNumber时Lerp()中最后一项的值才为1,所有比needPointNumber数多1
            for (int i = 0; i <= needPointNumber; i++)
            {
                //第一层
                Vector3 one1 = Vector3.Lerp(start.position, threeCenterPosArr[0].position, i / number);
                Vector3 one2 = Vector3.Lerp(threeCenterPosArr[0].position, threeCenterPosArr[1].position, i / number);
                Vector3 one3 = Vector3.Lerp(threeCenterPosArr[1].position, threeCenterPosArr[2].position, i / number);
                Vector3 one4 = Vector3.Lerp(threeCenterPosArr[2].position, end.position, i / number);
                //第二层
                Vector3 two1 = Vector3.Lerp(one1, one2, i / number);
                Vector3 two2 = Vector3.Lerp(one2, one3, i / number);
                Vector3 two3 = Vector3.Lerp(one3, one4, i / number);
                //第三层
                Vector3 three1 = Vector3.Lerp(two1, two2, i / number);
                Vector3 three2 = Vector3.Lerp(two2, two3, i / number);
                //目标层
                Vector3 targetPos = Vector3.Lerp(three1, three2, i / number);
                //将目标层放入我们的路径点中
                targetPosArr[i] = targetPos;
            }
            //在for循环结束之后得到所有的路径点
            return targetPosArr;
        }

        // 将目标物体从开始点移动到目标点通过平滑的曲线 额外的重载方法,就不仔细介绍了
        public static Vector3[] GetPathPoints(Vector3 startPos, Vector3 endPos, Vector3[] threeCenterPosArr, int needPointNumber = 20)
        {
            float number = (float)needPointNumber;
            Vector3[] targetPosArr = new Vector3[needPointNumber + 1];
            for (int i = 0; i <= number; i++)
            {
                //第一层
                Vector3 one1 = Vector3.Lerp(startPos, threeCenterPosArr[0], i / number);
                Vector3 one2 = Vector3.Lerp(threeCenterPosArr[0], threeCenterPosArr[1], i / number);
                Vector3 one3 = Vector3.Lerp(threeCenterPosArr[1], threeCenterPosArr[2], i / number);
                Vector3 one4 = Vector3.Lerp(threeCenterPosArr[2], endPos, i / number);
                //第二层
                Vector3 two1 = Vector3.Lerp(one1, one2, i / number);
                Vector3 two2 = Vector3.Lerp(one2, one3, i / number);
                Vector3 two3 = Vector3.Lerp(one3, one4, i / number);
                //第三层
                Vector3 three1 = Vector3.Lerp(two1, two2, i / number);
                Vector3 three2 = Vector3.Lerp(two2, two3, i / number);
                //目标层
                Vector3 targetPos = Vector3.Lerp(three1, three2, i / number);
                //将目标层放入我们的路径点中
                targetPosArr[i] = targetPos;
            }
            return targetPosArr;
        }

        //一个额外点的贝萨尔曲线(即抛物线)
        public static Vector3[] GetPathPoints(Vector3 startPos, Vector3 endPos, Vector3 centerPos, int needPointNumber = 20)
        {
            //为了节省性能
            //将其转化成;一个float,可以进行差值运算,否则结果为0
            float number = (float)needPointNumber;
            //定义一个数组,用来存放路径点,他的长度是从0 - needPointNumber的长度,及从0-1
            Vector3[] targetPosArr = new Vector3[needPointNumber + 1];
            //只有在等于needPointNumber时Lerp()中最后一项的值才为1,所有比needPointNumber数多1
            for (int i = 0; i <= needPointNumber; i++)
            {
                //第一层
                Vector3 one1 = Vector3.Lerp(startPos, centerPos, i / number);
                Vector3 one2 = Vector3.Lerp(centerPos, endPos, i / number);
                //目标层
                Vector3 targetPos = Vector3.Lerp(one1, one2, i / number);
                //将目标层放入我们的路径点中
                targetPosArr[i] = targetPos;
            }
            //在for循环结束之后得到所有的路径点
            return targetPosArr;
        }
    }
}